package handler

import (
	"fmt"
	"net/http"

	"github.com/emicklei/go-restful"
	log "github.com/golang/glog"
	"gopkg.in/mgo.v2"
	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

type APIHandler struct {
	mgoSession *mgo.Session
}

type User struct {
	Name     string `json:"u"`
	Password string `json:"p,omitempty"`
}

// CreateHTTPAPIHandler creates the restful Container and defines the routes the API will serve
func CreateHTTPAPIHandler(s *mgo.Session) (http.Handler, error) {
	session := s.Copy()
	apiHandler := APIHandler{
		mgoSession: session.Copy(),
	}
	defer session.Close()

	wsContainer := restful.NewContainer()

	wsContainer.EnableContentEncoding(true)

	cors := restful.CrossOriginResourceSharing{
		AllowedHeaders: []string{"Content-Type", "Accept"},
		AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},
		CookiesAllowed: true,
		Container:      wsContainer,
	}
	wsContainer.Filter(cors.Filter)
	wsContainer.Filter(wsContainer.OPTIONSFilter)

	apiV1Ws := new(restful.WebService)

	apiV1Ws.Path("/kronos/api").
		Consumes(restful.MIME_XML, restful.MIME_JSON).
		Produces(restful.MIME_JSON, restful.MIME_XML)

	apiV1Ws.Route(
		apiV1Ws.POST("/login").To(handleUserLogin))
	apiV1Ws.Route(
		apiV1Ws.PUT("/enroll").To(apiHandler.handleUserEnroll).
			Reads(User{}))

	wsContainer.Add(apiV1Ws)
	return wsContainer, nil
}

func handleUserLogin(request *restful.Request, response *restful.Response) {
	usr := new(User)
	if err := request.ReadEntity(usr); err != nil {
		if err2 := response.WriteError(http.StatusBadRequest, err); err2 != nil {
			log.Errorf("Failed to write response: %v", err2)
		}
		return
	}
	log.Infof("successfully handle User %v login", usr.Name)
	if err := response.WriteHeaderAndEntity(http.StatusOK, usr); err != nil {
		log.Errorf("Failed to write response: %v", err)
	}
}

func (apiHandler *APIHandler) handleUserEnroll(request *restful.Request, response *restful.Response) {
	usr := new(User)
	if err := request.ReadEntity(usr); err != nil {
		if err2 := response.WriteError(http.StatusBadRequest, err); err2 != nil {
			log.Errorf("Failed to write response: %v", err2)
		}
		return
	} else if usr.Name == "" {
		if err2 := response.WriteErrorString(http.StatusBadRequest, "name should not empty"); err2 != nil {
			log.Errorf("Failed to write response: %v", err2)
		}
		return
	}

	session := apiHandler.mgoSession.Copy()
	defer session.Close()

	c := session.DB("kronos").C("user")
	err := c.Insert(usr)
	if err != nil {
		if mgo.IsDup(err) {
			if err2 := response.WriteErrorString(http.StatusBadRequest, "name exist, try again"); err2 != nil {
				log.Errorf("Failed to write response: %v", err2)
			}
			return
		}
		if err2 := response.WriteError(http.StatusBadRequest, err); err2 != nil {
			log.Errorf("Failed to write response: %v", err2)
		}
		return
	}

	result := User{}
	iter := c.Find(nil).Iter()
	for iter.Next(&result) {
		fmt.Printf("Result: %v\n", result.Name)
	}

	fmt.Println("user:", result)

	var users []User
	c.Find(nil).All(&users)
	fmt.Println(users)

	//TODO: check if user.name has been used

	//create namespace with user.name, since user.name should be unique
	//namespace name = user.name

	//create ks env
	//apply ks
	//

	response.WriteHeader(http.StatusCreated)
}

func createNamespace(client *kubernetes.Clientset, namespace string) error {
	ns := &v1.Namespace{
		ObjectMeta: metav1.ObjectMeta{
			Name: namespace,
		},
	}
	_, err := client.Core().Namespaces().Create(ns)
	return err
}
